'use strict';

angular.module('xianwan').factory('UUID', function () {

    var maxFromBits = function (bits) {
        return Math.pow(2, bits);
    };

    var limitUI04 = maxFromBits(4);
    var limitUI06 = maxFromBits(6);
    var limitUI08 = maxFromBits(8);
    var limitUI12 = maxFromBits(12);
    var limitUI14 = maxFromBits(14);
    var limitUI16 = maxFromBits(16);
    var limitUI32 = maxFromBits(32);
    var limitUI40 = maxFromBits(40);
    var limitUI48 = maxFromBits(48);

    var getRandomInt = function (min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    var randomUI06 = function () {
        return getRandomInt(0, limitUI06 - 1);
    };

    var randomUI08 = function () {
        return getRandomInt(0, limitUI08 - 1);
    };

    var randomUI12 = function () {
        return getRandomInt(0, limitUI12 - 1);
    };

    var randomUI16 = function () {
        return getRandomInt(0, limitUI16 - 1);
    };

    var randomUI32 = function () {
        return getRandomInt(0, limitUI32 - 1);
    };

    var randomUI48 = function () {
        return (0 | Math.random() * (1 << 30)) + (0 | Math.random() * (1 << 48 - 30)) * (1 << 30);
    };

    var paddedString = function (string, length, z) {
        string = String(string);
        z = (!z) ? '0' : z;
        var i = length - string.length;
        for (; i > 0; i >>>= 1, z += z) {
            if (i & 1) {
                string = z + string;
            }
        }
        return string;
    };

    var fromParts = function (timeLow, timeMid, timeHiAndVersion, clockSeqHiAndReserved, clockSeqLow, node) {
        var hex = paddedString(timeLow.toString(16), 8)
            + '-'
            + paddedString(timeMid.toString(16), 4)
            + '-'
            + paddedString(timeHiAndVersion.toString(16), 4)
            + '-'
            + paddedString(clockSeqHiAndReserved.toString(16), 2)
            + paddedString(clockSeqLow.toString(16), 2)
            + '-'
            + paddedString(node.toString(16), 12);
        return hex;
    };

    return {
        generate: function () {
            return fromParts(
                randomUI32(),
                randomUI16(),
                0x4000 | randomUI12(),
                0x80 | randomUI06(),
                randomUI08(),
                randomUI48()
            );
        },

        // addition by Ka-Jan to test for validity
        // Based on: http://stackoverflow.com/questions/7905929/how-to-test-valid-uuid-guid
        validate: function (uuid) {
            var testPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
            return testPattern.test(uuid);
        }
    };

});
